﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Parser
{



    public struct operand
    {
        public int code;//0 - number, 1 - variable, 2 - binary operation, 3 - unary operation, 4 - ()
        public double value;
    }
    public struct operation
    {
        public operand oper;
        public int priority;
    }

    public class Parser
    {
        operand[] expression;
        int length;

        int IsOperand(char c)
        {
            int temp = (int)c;
            int result = -1;
            if ((temp >= 48) && (temp <= 57))
            {
                result = 0;
            }
            else if ((c == 'x') || (c == 'y'))
            {
                result = 1;
            }
            return result;
        }
        int IsFunction(char[] f)
        {
            int result = -1;
            if ((f[0] == 's') && (f[1] == 'i') && (f[2] == 'n'))
            {
                result = 0;
            }
            else if ((f[0] == 'c') && (f[1] == 'o') && (f[2] == 's'))
            {
                result = 2;
            }
            else if ((f[0] == 't') && (f[1] == 'a') && (f[2] == 'n'))
            {
                result = 3;
            }
            else if ((f[0] == 'c') && (f[1] == 't') && (f[2] == 'g'))
            {
                result = 4;
            }
            else if ((f[0] == 'e') && (f[1] == 'x') && (f[2] == 'p'))
            {
                result = 5;
            }
            return result;
        }
        int IsOperation(char c)
        {
            int result = -1;
            if (c == '+')
            {
                result = 0;
            }
            else if (c == '-')
            {
                result = 1;
            }
            else if (c == '*')
            {
                result = 2;
            }
            else if (c == '/')
            {
                result = 3;
            }
            else if (c == '^')
            {
                result = 4;
            }
            return result;
        }
        double CalcFunc(int code, double value)
        {
            double result;
            switch (code)
            {
                case 0: { result = Math.Sin(value); } break;
                case 1: { result = Math.Cos(value); } break;
                case 2: { result = Math.Tan(value); } break;
                case 3: { result = 1.0 / Math.Tan(value); } break;
                case 4: { result = Math.Exp(value); } break;
                default: { result = 0; } break;
            }
            return result;
        }
        double CalcOperation(int code, double value1, double value2)
        {
            double result;
            switch (code)
            {
                case 0: { result = value1 + value2; } break;
                case 1: { result = value1 - value2; } break;
                case 2: { result = value1 * value2; } break;
                case 3: { result = value1 / value2; } break;
                case 4: { result = Math.Pow(value1, value2); } break;
                default: { result = 0; } break;
            }
            return result;
        }
        public void Parse(char[] expr, int size)
        {
            int j = 0;
            char[] func = new char[3];
            char[] number = new char[11];
            operand temp;
            operation tmp;
            expression = new operand[size];
            length = 0;
            operation[] stack = new operation[size];
            int top = 0;
            int i = 0;
            if (expr[0] == '-')
            {
                temp.code = 0;
                temp.value = 0;
                expression[0] = temp;
                length++;
                tmp.oper.code = 2;
                tmp.oper.value = 1;
                tmp.priority = 1;
                stack[0] = tmp;
                top++;
                i++;
            }
            while (i < size)
            {
                if (expr[i] == '(')
                {
                    tmp.oper.code = 4;
                    tmp.oper.value = 0;
                    tmp.priority = 0;
                    stack[top] = tmp;
                    top++;
                    i++;
                }
                else if (expr[i] == ')')
                {
                    while (stack[top].oper.code != 4)
                    {
                        expression[length] = stack[top - 1].oper;
                        length++;
                        top--;
                    }
                    top--;
                    i++;
                }
                else if (IsOperand(expr[i]) != -1)
                {
                    temp.code = IsOperand(expr[i]);
                    if (temp.code == 0)
                    {
                        for (int k = 0; k < 11; k++)
                        {
                            number[k] = '0';
                        }
                        number[0] = expr[i];
                        j = 1;
                        i++;
                        while (IsOperand(expr[i]) != -1)
                        {
                            number[j] = expr[i];
                            j++;
                            i++;
                        }
                        if (expr[i] == ',')
                        {
                            number[j] = ',';
                            j++;
                            i++;
                            while ((IsOperand(expr[i]) != -1))
                            {
                                if (expr[i] == 'F')
                                { break; }
                                number[j] = expr[i];
                                j++;
                                i++;
                            }
                        }
                        else
                        {
                            number[j] = ',';
                        }
                        byte[] b;
                        b = new byte[11];
                        for (int ii = 0; ii < 11; ii++)
                        {
                            b[ii] = (byte)number[ii];
                        }
                        temp.value = Double.Parse(ASCIIEncoding.ASCII.GetString(b, 0, 11)); ;
                    }
                    else
                    {
                        temp.value = 0;
                        i++;
                    }
                    expression[length] = temp;
                    length++;
                }
                else if (IsOperation(expr[i]) != -1)
                {
                    tmp.oper.code = 2;
                    tmp.oper.value = IsOperation(expr[i]);
                    if (tmp.oper.value < 2)
                    {
                        tmp.priority = 1;
                    }
                    else if (tmp.oper.value < 4)
                    {
                        tmp.priority = 2;
                    }
                    else
                    {
                        tmp.priority = 3;
                    }

                    while (top > 0)
                    {
                        if ((tmp.priority > stack[top - 1].priority))
                        {
                            break;
                        }
                        expression[length] = stack[top - 1].oper;
                        length++;
                        top--;
                    }

                    stack[top] = tmp;
                    top++;
                    i++;
                }
                else
                {
                    for (int k = 0; k < 3; k++)
                    {
                        func[k] = expr[i + k];
                    }
                    tmp.priority = 5;
                    tmp.oper.code = 3;
                    tmp.oper.value = IsFunction(func);
                    stack[top] = tmp;
                    top++;
                    i += 3;
                }
                if (expr[i] == 'F')
                { break; }
            }
            while (top > 0)
            {
                expression[length] = stack[top - 1].oper;
                length++;
                top--;
            }
            stack = null;
            number = null;

        }
        public double Compute(double var)
        {
            double[] stack = new double[length];
            int top = 0;
            int i = 0;
            double value1, value2;
            while (i < length)
            {
                if (expression[i].code == 0)
                {
                    stack[top] = expression[i].value;
                    top++;
                }
                else if (expression[i].code == 1)
                {
                    stack[top] = var;
                    top++;
                }
                else if (expression[i].code == 2)
                {
                    value2 = stack[top - 1];
                    top--;
                    value1 = stack[top - 1];
                    stack[top - 1] = CalcOperation((int)expression[i].value, value1, value2);
                }
                else
                {
                    value1 = stack[top - 1];
                    stack[top - 1] = CalcFunc((int)expression[i].value, value1);
                }
                i++;
            }
            return stack[top - 1];
        }
    };
}
